package com.kaifamiao.socket;

import java.io.*;
import java.net.*;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Logger;

public class ThirdServer {

    private final Logger log = Logger.getLogger(this.getClass().getName());

    private final ExecutorService executorService = Executors.newScheduledThreadPool(10);

    private Map<String,Socket> socketMap = new HashMap<>();

    private String ip = "10.0.4.97";
    private int port = 54321;
    private ServerSocket serverSocket;

    private void create() {
        log.info("创建服务器");
        try {
            serverSocket = new ServerSocket();
        } catch (IOException cause) {
            throw new RuntimeException("服务器创建失败", cause);
        }
    }

    // 绑定IP地址和端口
    private void bind(){
        log.info("服务器初始化中...");
        InetAddress inetAddress = null;
        try {
            inetAddress = InetAddress.getByName(ip);
        } catch (UnknownHostException cause) {
            throw new RuntimeException("无法获取主机地址", cause);
        }

        if( inetAddress == null ) {
            throw new RuntimeException("无法获取主机地址");
        }

        SocketAddress serverAddress = new InetSocketAddress(inetAddress, port);
        try {
            serverSocket.bind( serverAddress );
        } catch (IOException cause) {
            throw new RuntimeException("IP地址和端口绑定失败", cause);
        }
    }

    private String identify(Socket socket) {
        // 获得远程主机地址 (因为是在服务器上获取，所以这里返回的是客户端的地址)
        InetSocketAddress sa = (InetSocketAddress)socket.getRemoteSocketAddress();
        String ip = sa.getAddress().getHostAddress();
        int port = sa.getPort();
        return String.format("[%s:%d]", ip, port);
    }

    // 监听客户端连接并为客户端提供服务
    private void service() {
        while(true) {
            log.info("正在监听客户端连接");
            Socket socket = null;
            try {
                socket = serverSocket.accept();
            } catch (IOException e) {
                log.warning("监听失败: " + e.getMessage());
            }
            if (socket == null) {
                continue;
            }
            // 用 ip 和 port 作为 标识符 来使用
            String identifier = identify(socket);
            // 将 监听到的 Socket 及其相应的标识符 添加到 Map集合中
            socketMap.put(identifier, socket);
            // 创建线程任务
            Runnable task = new ServiceTask(socket);
            // 向线程池提交任务
            executorService.submit(task);
        }
    }

    private class ServiceTask implements Runnable {

        private Socket socket;
        private String identifier;

        public ServiceTask(Socket socket) {
            this.socket = socket;
            // 调用宿主类的 identify 方法
            this.identifier = identify(socket);
        }

        @Override
        public void run() {
            try {
                InputStream in = socket.getInputStream();
                Reader r = new InputStreamReader(in);
                BufferedReader br = new BufferedReader(r);
                String message;
                while ((message = br.readLine()) != null) {
                    String str = String.format("%s说: %s", identifier, message);
                    System.out.println( str );
                    for( Socket s : socketMap.values() ) {
                        PrintStream ps = new PrintStream(s.getOutputStream());
                        ps.println(str);
                    }
                }
            } catch ( IOException e ) {
                e.printStackTrace();
            }
        }
    }

    public void launch() {
        create();
        bind();
        service();
    }

    public static void main(String[] args) {
        ThirdServer ts = new ThirdServer();
        ts.launch();
    }
}
